"""违规检测器模块"""

import cv2
import numpy as np
from typing import Dict, List, Tuple, Optional
import time
from config import get_config

class ViolationDetector:
    """交通违规检测器，用于检测各种交通违规行为"""
    
    def __init__(self):
        """初始化违规检测器"""
        # 违规检测参数
        self.min_violation_duration = get_config('behavior_analysis.violation_detector.min_duration', 2.0)  # 最小违规持续时间(秒)
        self.max_violation_interval = get_config('behavior_analysis.violation_detector.max_interval', 0.5)  # 违规间隔(秒)
        
        # 区域违规参数
        self.zone_violation_cooldown = get_config('behavior_analysis.violation_detector.zone_cooldown', 5.0)  # 区域违规冷却时间(秒)
        
        # 违规类型权重
        self.violation_weights = {
            'zone_violation': get_config('behavior_analysis.violation_detector.weights.zone_violation', 0.8),
            'wrong_direction': get_config('behavior_analysis.violation_detector.weights.wrong_direction', 0.9),
            'illegal_parking': get_config('behavior_analysis.violation_detector.weights.illegal_parking', 0.7),
            'pedestrian_violation': get_config('behavior_analysis.violation_detector.weights.pedestrian_violation', 1.0),
            'vehicle_overlap': get_config('behavior_analysis.violation_detector.weights.vehicle_overlap', 0.8)
        }
        
        # 跟踪违规状态
        self.violation_history = {}
        self.active_violations = {}
        self.zone_violation_times = {}
        
        # 区域设置
        self.restricted_zones = []
        self.pedestrian_crossings = []
        self.vehicle_directions = []
        self.bicycle_lanes = []
        self.parking_zones = []
        
        # 统计信息
        self.violation_stats = {
            'zone_violation': 0,
            'wrong_direction': 0,
            'illegal_parking': 0,
            'pedestrian_violation': 0,
            'vehicle_overlap': 0,
            'total': 0
        }
        
        print("违规检测器已初始化")
    
    def detect_violations(self, timestamp: float, detections: List[Dict], 
                         tracking_results: List[Dict], traffic_results: Dict = None) -> List[Dict]:
        """检测各种交通违规行为
        
        Args:
            timestamp: 当前时间戳
            detections: 检测结果
            tracking_results: 跟踪结果
            traffic_results: 交通分析结果
            
        Returns:
            违规检测结果列表
        """
        all_violations = []
        
        # 检测行人违规（如闯红灯、不按规定通行等）
        pedestrian_violations = self._detect_pedestrian_violations(timestamp, detections, tracking_results)
        all_violations.extend(pedestrian_violations)
        
        # 检测车辆重叠/碰撞风险
        overlap_violations = self._detect_vehicle_overlap(timestamp, detections)
        all_violations.extend(overlap_violations)
        
        # 检测区域违规
        zone_violations = self._detect_zone_violations(timestamp, tracking_results)
        all_violations.extend(zone_violations)
        
        # 检测逆向行驶
        direction_violations = self._detect_direction_violations(timestamp, tracking_results)
        all_violations.extend(direction_violations)
        
        # 检测违章停车
        parking_violations = self._detect_illegal_parking(timestamp, tracking_results)
        all_violations.extend(parking_violations)
        
        # 更新活跃违规状态
        self._update_active_violations(timestamp)
        
        return all_violations
    
    def _detect_pedestrian_violations(self, timestamp: float, detections: List[Dict], 
                                     tracking_results: List[Dict]) -> List[Dict]:
        """检测行人违规（如闯红灯、不按规定通行等）
        
        Args:
            timestamp: 当前时间戳
            detections: 检测结果
            tracking_results: 跟踪结果
            
        Returns:
            行人违规结果列表
        """
        violations = []
        
        # 找出所有行人检测结果
        pedestrian_detections = [d for d in detections if d.get('class') == 'person']
        
        for detection in pedestrian_detections:
            # 获取行人的边界框
            bbox = detection.get('bbox', [])
            if len(bbox) < 4:
                continue
                
            # 简化的违规检测：检查行人是否在车辆行驶区域
            # 实际项目中应根据交通灯状态、人行横道位置等进行更复杂的判断
            is_violating = False
            reason = ""
            
            # 检查是否在车辆专用区域
            for direction in self.vehicle_directions:
                if self._is_bbox_in_zone(bbox, direction):
                    is_violating = True
                    reason = "行人进入车辆专用区域"
                    break
            
            if is_violating:
                # 创建唯一的违规ID
                violation_id = f"pedestrian_{id(detection)}"
                
                # 更新违规历史
                if violation_id not in self.violation_history:
                    self.violation_history[violation_id] = {
                        'start_time': timestamp,
                        'last_seen': timestamp,
                        'type': 'pedestrian_violation',
                        'pedestrian_info': detection,
                        'duration': 0,
                        'reason': reason
                    }
                else:
                    # 更新最后看到的时间
                    self.violation_history[violation_id]['last_seen'] = timestamp
                    self.violation_history[violation_id]['duration'] = timestamp - self.violation_history[violation_id]['start_time']
                
                # 检查是否达到最小违规持续时间
                violation = self.violation_history[violation_id]
                if violation['duration'] >= self.min_violation_duration:
                    violation_result = {
                        'timestamp': timestamp,
                        'type': 'pedestrian_violation',
                        'severity': self.violation_weights['pedestrian_violation'],
                        'location': {
                            'x1': bbox[0],
                            'y1': bbox[1],
                            'x2': bbox[2],
                            'y2': bbox[3]
                        },
                        'reason': violation['reason'],
                        'duration': violation['duration'],
                        'confidence': detection.get('confidence', 0.9)
                    }
                    violations.append(violation_result)
                    
                    # 更新活跃违规
                    self.active_violations[violation_id] = violation_result
                    
                    # 更新统计
                    self.violation_stats['pedestrian_violation'] += 1
                    self.violation_stats['total'] += 1
        
        return violations
    
    def _detect_vehicle_overlap(self, timestamp: float, detections: List[Dict]) -> List[Dict]:
        """检测车辆重叠/碰撞风险
        
        Args:
            timestamp: 当前时间戳
            detections: 检测结果
            
        Returns:
            车辆重叠违规结果列表
        """
        violations = []
        vehicle_classes = ['car', 'bicycle', 'motorbike', 'truck', 'bus']
        vehicle_detections = [d for d in detections if d.get('class') in vehicle_classes]
        
        # 检查每对车辆是否重叠
        for i in range(len(vehicle_detections)):
            for j in range(i + 1, len(vehicle_detections)):
                det1 = vehicle_detections[i]
                det2 = vehicle_detections[j]
                
                bbox1 = det1.get('bbox', [])
                bbox2 = det2.get('bbox', [])
                
                if len(bbox1) < 4 or len(bbox2) < 4:
                    continue
                
                # 计算重叠比例
                overlap_ratio = self._calculate_overlap_ratio(bbox1, bbox2)
                
                # 如果重叠比例超过阈值，则认为存在碰撞风险
                if overlap_ratio > 0.1:  # 10%的重叠作为阈值
                    violation_id = f"overlap_{i}_{j}_{timestamp}"
                    
                    # 创建违规结果
                    violation_result = {
                        'timestamp': timestamp,
                        'type': 'vehicle_overlap',
                        'severity': self.violation_weights['vehicle_overlap'],
                        'vehicles': [
                            {
                                'class': det1.get('class'),
                                'confidence': det1.get('confidence'),
                                'bbox': bbox1
                            },
                            {
                                'class': det2.get('class'),
                                'confidence': det2.get('confidence'),
                                'bbox': bbox2
                            }
                        ],
                        'overlap_ratio': overlap_ratio,
                        'location': {
                            'x1': min(bbox1[0], bbox2[0]),
                            'y1': min(bbox1[1], bbox2[1]),
                            'x2': max(bbox1[2], bbox2[2]),
                            'y2': max(bbox1[3], bbox2[3])
                        }
                    }
                    violations.append(violation_result)
                    
                    # 更新统计
                    self.violation_stats['vehicle_overlap'] += 1
                    self.violation_stats['total'] += 1
        
        return violations
    
    def _is_bbox_in_zone(self, bbox: List[float], zone: List[Tuple[float, float]]) -> bool:
        """检查边界框是否在指定区域内
        
        Args:
            bbox: 边界框坐标 [x1, y1, x2, y2]
            zone: 区域多边形顶点列表
            
        Returns:
            是否在区域内
        """
        # 简化实现：检查边界框中心点是否在区域内
        center_x = (bbox[0] + bbox[2]) / 2
        center_y = (bbox[1] + bbox[3]) / 2
        
        # 使用射线法判断点是否在多边形内
        # 这里简化为矩形区域的判断
        if len(zone) >= 4:
            # 假设zone是矩形的四个顶点
            min_x = min(p[0] for p in zone)
            max_x = max(p[0] for p in zone)
            min_y = min(p[1] for p in zone)
            max_y = max(p[1] for p in zone)
            
            return min_x <= center_x <= max_x and min_y <= center_y <= max_y
        
        return False
    
    def _calculate_overlap_ratio(self, bbox1: List[float], bbox2: List[float]) -> float:
        """计算两个边界框的重叠比例
        
        Args:
            bbox1: 第一个边界框坐标 [x1, y1, x2, y2]
            bbox2: 第二个边界框坐标 [x1, y1, x2, y2]
            
        Returns:
            重叠比例 (0-1)
        """
        # 计算交集区域
        x1 = max(bbox1[0], bbox2[0])
        y1 = max(bbox1[1], bbox2[1])
        x2 = min(bbox1[2], bbox2[2])
        y2 = min(bbox1[3], bbox2[3])
        
        # 检查是否有重叠
        if x1 >= x2 or y1 >= y2:
            return 0.0
        
        # 计算交集面积
        intersection_area = (x2 - x1) * (y2 - y1)
        
        # 计算两个边界框的面积
        area1 = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
        area2 = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
        
        # 计算并集面积
        union_area = area1 + area2 - intersection_area
        
        # 计算重叠比例（相对于较小的边界框）
        smaller_area = min(area1, area2)
        overlap_ratio = intersection_area / smaller_area if smaller_area > 0 else 0.0
        
        return overlap_ratio
    
    def _detect_zone_violations(self, timestamp: float, tracking_results: List[Dict]) -> List[Dict]:
        """检测区域违规（如进入禁行区域）
        
        Args:
            timestamp: 当前时间戳
            tracking_results: 跟踪结果
            
        Returns:
            区域违规结果列表
        """
        violations = []
        
        for zone in self.restricted_zones:
            zone_id = zone['id']
            zone_points = np.array(zone['points'], dtype=np.int32)
            
            # 检查冷却时间
            if zone_id in self.zone_violation_times:
                if timestamp - self.zone_violation_times[zone_id] < self.zone_violation_cooldown:
                    continue
            
            # 检查每个跟踪目标是否在区域内
            for track in tracking_results:
                track_id = track['track_id']
                bbox_center = self._get_center(track)
                
                # 判断点是否在多边形内
                if cv2.pointPolygonTest(zone_points, bbox_center, False) >= 0:
                    # 检查是否为违规目标类型
                    if track['class_name'] in zone.get('prohibited_classes', []):
                        violation_id = f"zone_{zone_id}_track_{track_id}"
                        
                        # 记录违规
                        violation_result = {
                            'timestamp': timestamp,
                            'type': 'zone_violation',
                            'severity': self.violation_weights['zone_violation'],
                            'location': {
                                'x1': track['x1'],
                                'y1': track['y1'],
                                'x2': track['x2'],
                                'y2': track['y2']
                            },
                            'zone_id': zone_id,
                            'zone_name': zone.get('name', f'Zone {zone_id}'),
                            'track_id': track_id,
                            'class_name': track['class_name']
                        }
                        violations.append(violation_result)
                        
                        # 更新区域违规时间
                        self.zone_violation_times[zone_id] = timestamp
                        
                        # 更新活跃违规
                        self.active_violations[violation_id] = violation_result
        
        return violations
    
    def _detect_direction_violations(self, timestamp: float, tracking_results: List[Dict]) -> List[Dict]:
        """检测逆向行驶
        
        Args:
            timestamp: 当前时间戳
            tracking_results: 跟踪结果
            
        Returns:
            方向违规结果列表
        """
        violations = []
        
        # 这里需要轨迹信息才能检测逆向行驶
        # 简化版本：检查目标是否在指定的自行车道或车道上，且移动方向与规定方向相反
        
        for direction in self.vehicle_directions:
            lane_points = np.array(direction['lane_points'], dtype=np.int32)
            allowed_direction = direction['allowed_direction']  # 允许的方向向量
            
            for track in tracking_results:
                # 检查目标是否在车道内
                track_center = self._get_center(track)
                if cv2.pointPolygonTest(lane_points, track_center, False) >= 0:
                    # 检查目标类型是否与车道匹配
                    if track['class_name'] in direction.get('allowed_classes', []):
                        # 这里简化处理，实际应该跟踪历史轨迹计算移动方向
                        # 示例：假设通过目标的位置变化来判断
                        # 此处仅作示例，实际实现需要更复杂的轨迹分析
                        pass
        
        return violations
    
    def _detect_illegal_parking(self, timestamp: float, tracking_results: List[Dict]) -> List[Dict]:
        """检测违章停车
        
        Args:
            timestamp: 当前时间戳
            tracking_results: 跟踪结果
            
        Returns:
            违章停车结果列表
        """
        violations = []
        
        # 这里需要轨迹信息才能检测停车行为
        # 简化版本：检查目标是否在禁止停车区域内停留时间过长
        
        for track in tracking_results:
            track_id = track['track_id']
            
            # 检查是否为车辆类型
            if track['class_name'] in ['car', 'truck', 'bus', 'motorcycle']:
                # 这里简化处理，实际应该跟踪历史位置计算停留时间
                # 示例：通过位置变化量判断是否静止
                # 此处仅作示例，实际实现需要更复杂的轨迹分析
                pass
        
        return violations
    
    def _update_active_violations(self, timestamp: float) -> None:
        """更新活跃违规状态，移除过期的违规
        
        Args:
            timestamp: 当前时间戳
        """
        expired_violations = []
        
        for violation_id, violation in self.active_violations.items():
            # 检查违规是否已过期
            if timestamp - violation['timestamp'] > self.max_violation_interval:
                expired_violations.append(violation_id)
                
                # 更新统计信息
                self._update_violation_statistics(violation['type'])
        
        # 移除过期的违规
        for violation_id in expired_violations:
            if violation_id in self.active_violations:
                del self.active_violations[violation_id]
    
    def _update_violation_statistics(self, violation_type: str) -> None:
        """更新违规统计信息
        
        Args:
            violation_type: 违规类型
        """
        if violation_type in self.violation_stats:
            self.violation_stats[violation_type] += 1
            self.violation_stats['total'] += 1
    
    def _get_center(self, bbox: Dict) -> Tuple[int, int]:
        """获取边界框中心点
        
        Args:
            bbox: 边界框字典
            
        Returns:
            (中心x坐标, 中心y坐标)
        """
        center_x = (bbox['x1'] + bbox['x2']) // 2
        center_y = (bbox['y1'] + bbox['y2']) // 2
        return (center_x, center_y)
    
    def add_restricted_zone(self, zone_id: str, name: str, points: List[Tuple], 
                           prohibited_classes: List[str] = None) -> None:
        """添加禁行区域
        
        Args:
            zone_id: 区域ID
            name: 区域名称
            points: 区域多边形点列表
            prohibited_classes: 禁止进入的类别列表
        """
        if prohibited_classes is None:
            prohibited_classes = ['person', 'bicycle', 'motorcycle']
        
        self.restricted_zones.append({
            'id': zone_id,
            'name': name,
            'points': points,
            'prohibited_classes': prohibited_classes
        })
    
    def add_bicycle_lane(self, lane_id: str, name: str, points: List[Tuple]) -> None:
        """添加自行车道
        
        Args:
            lane_id: 车道ID
            name: 车道名称
            points: 车道多边形点列表
        """
        self.bicycle_lanes.append({
            'id': lane_id,
            'name': name,
            'points': points
        })
    
    def add_vehicle_direction(self, lane_id: str, lane_points: List[Tuple], 
                             allowed_direction: Tuple, allowed_classes: List[str]) -> None:
        """添加车辆行驶方向限制
        
        Args:
            lane_id: 车道ID
            lane_points: 车道多边形点列表
            allowed_direction: 允许的行驶方向向量
            allowed_classes: 允许的车辆类别
        """
        self.vehicle_directions.append({
            'lane_id': lane_id,
            'lane_points': lane_points,
            'allowed_direction': allowed_direction,
            'allowed_classes': allowed_classes
        })
    
    def clear_all_zones(self) -> None:
        """清除所有区域设置"""
        self.restricted_zones.clear()
        self.bicycle_lanes.clear()
        self.vehicle_directions.clear()
    
    def get_violation_statistics(self) -> Dict:
        """获取违规统计信息
        
        Returns:
            违规统计信息字典
        """
        return self.violation_stats.copy()
    
    def get_active_violations(self) -> Dict:
        """获取当前活跃的违规
        
        Returns:
            活跃违规字典
        """
        return self.active_violations.copy()
    
    def set_violation_params(self, min_duration: float = None, 
                           max_interval: float = None,
                           zone_cooldown: float = None) -> None:
        """设置违规检测参数
        
        Args:
            min_duration: 最小违规持续时间
            max_interval: 违规间隔时间
            zone_cooldown: 区域违规冷却时间
        """
        if min_duration is not None:
            self.min_violation_duration = min_duration
        if max_interval is not None:
            self.max_violation_interval = max_interval
        if zone_cooldown is not None:
            self.zone_violation_cooldown = zone_cooldown
    
    def set_violation_weights(self, weights: Dict) -> None:
        """设置违规权重
        
        Args:
            weights: 违规类型权重字典
        """
        for violation_type, weight in weights.items():
            if violation_type in self.violation_weights:
                self.violation_weights[violation_type] = weight

# 创建全局违规检测器实例
violation_detector = ViolationDetector()

# 导出常用方法
def get_violation_detector() -> ViolationDetector:
    """获取违规检测器实例的快捷方法"""
    return violation_detector